Function类型

描述

  • 在JavaScript中的所有函数都是Function类型的对象

定义函数的方式

函数声明方式

function 函数名 () { 
    函数体 
}
/* 函数声明方式定义函数 */
function fun() {
    console.log( '函数声明方式...' );
}
fun();// 显示 函数声明方式...

字面量方式

var 函数名 = function () { 
    函数体 
}
/* 字面量方式定义函数 */
var fu = function () {
    console.log( '字面量方式...' );
}
fu();// 显示 字面量方式...

构造函数方式

var 函数名 = new Function( 参数,函数体 )
  • 函数的参数和函数体,都以字符串形式填写在括号中,以逗号分隔
  • 在使用构造函数创建一个Function类型的对象时,会得到一个函数
/* 构造函数方式定义函数 */
var fn = new Function( 'can', 'console.log( can )' );
fn('构造函数方式...');// 显示 构造函数方式...

判断定义的函数是否为Function类型

/* 函数声明方式 */
console.log( fun instanceof Function );// true
/* 字面量方式 */
console.log( fu instanceof Function );// true
/* 构造函数方式 */
console.log( fn instanceof Function );// true

apply()方法

  • 表示用于调用指定函数
  • 该方法接收两个参数

    • 第一个 - this
    • 第二个 - 一个数组

      • 该数组用于存储指定函数的所有参数(实参)
/* 定义一个函数 */
function fun( can ) {
    console.log( can );
}
/* 根据函数语法正常调用函数 */
fun( '这是一个函数' );// 显示 这是一个函数

/*
    根据Function对象提供的apply()方法进行函数调用
     * 参数 this 可以先用 null 站位
 */
fun.apply( null, ['这还是一个函数'] );// 显示 这还是一个函数

call()方法

  • 表示用于调用指定函数
  • 该方法接收两个参数

    • 第一个 - this
    • 第二个 - 函数的参数
      -需求多少参数,写多少参数,使用逗号分隔
/* 定义一个函数 */
function fun( can, shu ) {
    console.log( can + shu );
}
/* 根据函数语法正常调用函数 */
fun( '这是一个函数', '...' );// 显示 这是一个函数...

/*
    根据Function对象提供的call()方法进行函数调用
     * 参数 this 可以先用 null 站位
 */
fun.call( null, '这还是一个函数', '...' );// 显示 这还是一个函数...

bind()方法

  • 表示创建一个新的函数(称为绑定函数)
  • 该方法接收两个参数

    • 第一个 - this
    • 第二个 - 函数的参数

      • 需求多少参数,写多少参数,使用逗号分隔
  • 该方法的返回值 - 返回一个新的函数

    • 返回的新函数 - 是对指定函数进行复制得到的
    • 两个函数对函数体进行修改不会相互影响
/* 定义一个函数 */
function fun( can, shu ) {
    console.log( can + shu );
}
/* 根据函数语法正常调用函数 - 对参数进行修改 */
fun( '...', '这是一个函数' );// 显示 这是一个函数...   修改后显示 ...这是一个函数

/*
    根据Function对象提供的bind()方法进行函数调用
     * 参数 this 可以先用 null 站位
     * 两个函数之间不会有影响
 */
var fn = fun.bind( null, '这还是一个函数', '...' );
fn();// 显示 这还是一个函数...

重载

  • 表示定义多个同名的函数,但每个函数可接收的参数不同
  • 在调用时会进行判断,函数会根据形参可接收的个数去匹配传入实参个数相同的

注意

  • 在JavaScript的函数中不存在重载
  • 当函数同名时,最后一次定义的函数有效
/* 重载现象 */
function fn( a, b ){
    return a + b;
}
function fn( a, b, c ){
    return a + b + c;
}
function fn( a, b, c, d ){
    return a + b + c + d;
}
/* 重载的正常显示 */
fn( 1, 2 );// 显示 3
fn( 1, 2, 3 );// 显示 6
fn( 1, 2, 3, 4 );// 显示 10
/* JavaScript中的显示结果 */
console.log( fn( 1, 2 ) );// 显示 NaN
console.log( fn( 1, 2, 3 ) );// 显示 NaN
console.log( fn( 1, 2, 3, 4 ) );// 显示 10

arguments对象

  • 该对象可以获取当前指定函数中的所以参数(实参),并存储到一个类数组中
  • 该对象只能在函数中使用
  • length属性 - 表示函数中参数的个数
  • 该方法可以模拟实现函数的重载
function fun(){
    /* 通过length属性获取函数参数的个数 */
    var add = arguments.length;
    /* 再通过条件语句进行判断 */
    switch ( add ) {
        /* 根据参数的个数进行显示 */
        case 2:
            /* 由于arguments对象将获取到的参数储存到一个类数组中,可以使用数组的方式进行提取 */
            return arguments[0] + arguments[1];
            break;
        case 3:
            return arguments[0] + arguments[1] + arguments[2];
            break;
        case 4:
            return arguments[0] + arguments[1] + arguments[2] + arguments[3];
            break;
    }
}
/* 可以模拟出重载的效果 */
console.log( fun( 1, 2 ) );// 显示 3
console.log( fun( 1, 2, 3 ) );// 显示 6
console.log( fun( 1, 2, 3, 4 ) );// 显示 10

递归

  • 表示在一个函数中,调用自身

注意

  • 如果不给递归设置一个出口,会出现类似于循环语句中的 死循环

解决

  • 通过在递归的过程中不断改变数据值
  • 在进行条件判断来设置出口
  • 利用return语句的结束效果,结束递归

arguments对象的callee属性

  • 该属性表示当前正在执行的函数
function fun() {
    console.log( '啊哈哈' );
    /*
        调用自身函数 - 实现递归
         * 会出现类似于循环语句中的 死循环
     */
    fun();
}
fun();

/* 可以设置一个循环出口 */
function fn( a ) {
    console.log( a );
    /* 通过条件判断来设置出口 */
    if ( a >= 10 ) {
        /* 利用return语句的结束效果,结束递归 */
        return;
    }
    /* 在递归的过程中不断改变数据值 */
    fn( a + 1 );
}
/* 传入一个数值用于条件判断 */
fn( 0 );

/* 如果将递归函数赋值个一个变量,再将递归函数清空释放,在去执行变量会出错 */
function fu( b ) {
    console.log( b );
    if ( b >= 10 ) {
        return;
    }
    /*
        新函数(s)在执行时,内部的函数体,依然是旧函数(fu)的
        当执行到改变数据值时,调用的目标依旧是旧函数(fu)而没有更改成新函数(s)
        所以会报错 - TypeError: fu is not a function

        可以通过arguments对象的callee属性去替换函数名
        arguments对象的callee属性
         * 该属性表示当前正在执行的函数
     */
    // fu( b + 1 );
    /* 修改后在执行就可正常显示 */
    arguments.callee( b + 1 );
}
fu( 0 );
/* 将递归函数赋值个一个变量 */
var s = fu;
/* 将递归函数清空释放 */
fu = null;
/* 使用函数方式执行变量 */
s( 0 );
/* 会报错 */
console.log( s );// 显示 fu is not a function

匿名函数

  • 表示定义一个没有函数名的函数

匿名函数的用法

  • 将匿名函数作为参数传递给其他函数

    • 这种方法也可以叫做 回调函数
  • 将匿名函数用于执行一次性任务

    • 这种方法也可以叫做 自调函数
/* 创建一个匿名函数 */
function (){
    console.log( '啊哈哈' );
}

回调函数

  • 表示一个函数做为参数传入到另一个函数中
/* 定义一个函数 - 该函数做为另一个函数的参数 */
var fn = function () {
    return 10;
}

/* 定义另一个函数 */
var fun = function ( f ) {
    /* 传进该函数体中的是一个函数,可以直接调用 */
    return f();
}
/* 当前函数的参数为另一个函数 */
var s = fun( fn );
console.log( s );// 显示 10

自调函数

  • 表示在定义函数后自行调用

用法

  • 第一种 - 两个小括号

    • 第一个小括号 - 定义匿名函数
    • 第二个小括号 - 调用
/* 第一种方法 */
(function(){
    console.log( '啊哈哈' );
})();
  • 第二种 - 一个小括号中包含另一个小括号

    • 第一个小括号 - 定义匿名函数
    • 第二个小括号(被包含的) - 调用
/* 第二种方法 */
(function(){
    console.log( '呀吼吼' );
}());
  • 第三种 - 叹号 + 小括号

    • 叹号后写匿名函数
    • 小括号 - 调用
/* 第三种方法 */
!function(){
    console.log( '哦哦哦' );
}();

作为值的函数

  • 表示一个函数做为另一个函数的返回值
function fun() {
    var s = 10;
    return function () {
        return s;
    }
}
console.log( fun()() );// 显示 10

作用域链

  • 表示函数作用域有权限访问除自身内部的函数作用域之外的其他作用域
  • 并且会把次特性传递个自身内部的函数作用域
var a = 100;// 全局变量
function fun1(){
    var b = 200;// fun1函数作用域的局部变量
    // 内部函数
    function fun2(){
        var c = 300;// fun2函数作用域的局部变量
        // 内部函数
        function fun3(){
            var d = 400;// fun3函数作用域的局部变量
            // 调用变量
            console.log(a);// 100
            console.log(b);// 200
            console.log(c);// 300
            console.log(d);// 400
        }
        fun3();
        // 调用变量
        // console.log(a);// 100
        // console.log(b);// 200
        // console.log(c);// 300
        // console.log(d);// d is not defined
    }
    fun2();
    // 调用变量
    // console.log(a);// 100
    // console.log(b);// 200
    // console.log(c);// c is not defined
    // console.log(d);// d is not defined
}
fun1();

闭包理论

  • 表示在全局作用域可以访问到函数作用域中的数据
  • 作用域的逆向操作(个人理解)
/* 定义一个全局变量但不赋值 */
var s;
function fun(){
    var v = 100;
    /* 在函数作用域中对全局变量进行赋值 */
    s = function(){
        console.log(v);
    }
    s();
}
fun();// 显示函数体的内容 100
/* 访问全局变量会得到在函数作用域中数值 */
s();// 显示全局变量的值 100

蔡志远
9 声望5 粉丝